/*
判断Rpc请求函数名称、函数参数是否合法，如果合法，调用相应的回调函数
*/

#pragma once

#include "../Common/Net.hpp"
#include "../Common/Message.hpp"

#include <functional>

namespace RpcModule
{
    namespace ServerModule
    {
        enum class RpcType
        {
            BOOL = 0, // 布尔类型
            INTEGRAL, // 整形
            NUMERIC,  // 浮点型
            STRING,   // 字符串
            ARRAY,    // 数组
            OBJECT    // 对象(Json)
        };

        // 服务描述类 -- 提供了参数的判断
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallBack = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamsDescribe = std::pair<std::string, RpcType>;
            ServiceDescribe(const std::string &&name, const ServiceCallBack &&handler,
                            std::vector<ParamsDescribe> &&desc, RpcType return_type)
                : _method_name(std::move(name)), _callback(std::move(handler)),
                  _params_desc(std::move(desc)), _return_type(return_type) {}

            const std::string &GetMethodName() { return _method_name; }
            // 参数校验逻辑实现
            bool ParamCheck(const Json::Value &params)
            {
                // 1. 判断参数名称是否存在 -- num1是否存在
                for (auto &desc : _params_desc)
                {
                    // desc -- <num1, int>
                    // params[num1] : 11
                    // isMember -- 判断Json中是否有num1对象
                    if (params.isMember(desc.first) == false)
                    {
                        LOGERROR("Json中不存在%s字段", desc.first.c_str());
                        return false;
                    }
                    if (Check(desc.second, params[desc.first]) == false)
                    {
                        LOGERROR("参数%s类型错误！", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            // 进行回调调用，传入参数，通过result输出返回值
            bool Call(const Json::Value &params, Json::Value &result)
            {
                _callback(params, result);
                if (ReturnTypeCheck(result) == false)
                {
                    LOGERROR("回调函数中，结果的返回值错误！");
                    return false;
                }
                return true;
            }

        private:
            bool ReturnTypeCheck(Json::Value &result)
            {
                return Check(_return_type, result);
            }

            bool Check(RpcType type, const Json::Value &value)
            {
                switch (type)
                {
                case RpcType::BOOL:
                    return value.isBool();
                case RpcType::INTEGRAL:
                    return value.isIntegral();
                case RpcType::NUMERIC:
                    return value.isNumeric();
                case RpcType::STRING:
                    return value.isString();
                case RpcType::ARRAY:
                    return value.isArray();
                case RpcType::OBJECT:
                    return value.isObject();
                }
                return false;
            }

        private:
            std::string _method_name;                 // 方法名称
            ServiceCallBack _callback;                // 回调函数
            std::vector<ParamsDescribe> _params_desc; // 参数描述
            RpcType _return_type;                     // 返回类型描述
        };
        class ServiceDescribeFactory
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribeFactory>;
            // 这里是构造者模式，用户进行各种信息的设置，然后在这里进行服务描述类的构造
            void SetMethodName(const std::string &name) { _method_name = name; }
            void SetReturnType(RpcType return_type) { _return_type = return_type; }
            void SetCallBack(const ServiceDescribe::ServiceCallBack &cb) { _callback = cb; }
            void SetParamsDesc(const std::string &name, RpcType type)
            {
                _params_desc.push_back(std::make_pair(name, type));
            }
            ServiceDescribe::ptr Build()
            {
                return std::make_shared<ServiceDescribe>(std::move(_method_name), std::move(_callback),
                                                         std::move(_params_desc), _return_type);
            }

        private:
            std::string _method_name;                                  // 方法名称
            ServiceDescribe::ServiceCallBack _callback;                // 回调函数
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc; // 参数描述
            RpcType _return_type;                                      // 返回类型描述
        };

        // 服务管理类 -- 对于大量的服务，需要进行管理
        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;
            // 增加服务
            void Create(const ServiceDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.insert(std::make_pair(desc->GetMethodName(), desc));
            }
            // 查询服务
            ServiceDescribe::ptr Select(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(method_name);
                if (it == _services.end())
                    return ServiceDescribe::ptr();
                return it->second;
            }
            // 删除服务
            void Remove(const std::string &method_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _services.erase(method_name);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _services;
        };

        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manager(std::make_shared<ServiceManager>()) {}
            // 进行服务的注册
            void RegisterMethod(const ServiceDescribe::ptr &service)
            {
                return _service_manager->Create(service);
            }
            // Rpc调用的回调函数
            void OnRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                // 1. 查询请求的方法名称，判断服务端是否能提供该方法的服务
                ServiceDescribe::ptr service = _service_manager->Select(request->GetRpcMethod());
                if (service.get() == nullptr)
                {
                    LOGERROR("不存在%s方法", request->GetRpcMethod().c_str());
                    return Response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                // 2. 进行参数校验
                if (service->ParamCheck(request->GetRpcParams()) == false)
                {
                    LOGERROR("参数校验失败！");
                    return Response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                // 3. 调用相应的业务处理回调函数
                Json::Value result;
                bool ret = service->Call(request->GetRpcParams(), result);
                if (ret == false)
                {
                    LOGERROR("服务函数调用失败！");
                    return Response(conn, request, result, RCode::RCODE_INTERNAL_ERROR);
                }
                // 4. 处理完毕得到结果，发送给客户端
                return Response(conn, request, result, RCode::RCODE_OK);
            }

        private:
            void Response(const BaseConnection::ptr &conn, const RpcRequest::ptr &request, const Json::Value &value, RCode rcode)
            {
                // 1. 发送给客户端，先构建发送的消息对象
                auto message = MessageFactory::CreateMessage<RpcResponse>();
                message->SetId(request->GetRid());
                message->SetMType(MType::RSP_RPC);
                message->SetRcode(rcode);
                message->SetResult(value);
                // 2. 直接发送给客户端
                conn->Send(message);
            }

        private:
            ServiceManager::ptr _service_manager;
        };
    }
}